﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Radar.Navigation;
using Jage.Utils;

namespace Radar.Optimization
{
    internal class GridFactory
        : SingletonBase<GridFactory>
    {

        private Grid _grid;

        internal Grid CreateGrid(NavZone[] zones, int columnCount, int rowCount)
        {
            _grid = new Grid(columnCount, rowCount);
            CalculateBounds(zones);
            CalculateGridCellSize();
            CalculateZonesPerGridCell(zones);
            return _grid;
        }

        private void CalculateBounds(NavZone[] zones)
        {
            int count = zones.Length;
            if (count > 0)
            {
                NavZone zone = zones[0];
                _grid.LeftBound = zone.Left;
                _grid.TopBound = zone.Top;
                _grid.RightBound = zone.Right;
                _grid.BottomBound = zone.Bottom;
                for (int i = 1; i < count; i++)
                {
                    zone = zones[i];
                    if (zone.Left < _grid.LeftBound) _grid.LeftBound = zone.Left;
                    if (zone.Top < _grid.TopBound) _grid.TopBound = zone.Top;
                    if (zone.Right > _grid.RightBound) _grid.RightBound = zone.Right;
                    if (zone.Bottom > _grid.BottomBound) _grid.BottomBound = zone.Bottom;
                }
            }
            else
            {
                throw new ApplicationException("There are no Zones.");
            }
        }

        private void CalculateGridCellSize()
        {
            _grid.CellWidth = (int)Math.Ceiling((_grid.RightBound - _grid.LeftBound) / (float)_grid.ColumnCount);
            _grid.CellHeight = (int)Math.Ceiling((_grid.BottomBound - _grid.TopBound) / (float)_grid.RowCount);
        }

        private void CalculateZonesPerGridCell(NavZone[] zones)
        {
            _grid.Cells = new GridCell[_grid.ColumnCount, _grid.RowCount];
            for (int x = 0; x < _grid.ColumnCount; x++)
            {
                for (int y = 0; y < _grid.RowCount; y++)
                {
                    var cell = new GridCell();
                    _grid.Cells[x, y] = cell;
                    var rectangle = new Rectangle(_grid.LeftBound + x * _grid.CellWidth, _grid.TopBound + y * _grid.CellHeight, _grid.CellWidth, _grid.CellHeight);
                    cell.ZonesTouching = GetZonesTouching(zones, rectangle);
                    cell.ZonesStarting = GetZonesStarting(zones, rectangle);
                }
            }
        }

        private NavZone[] GetZonesTouching(NavZone[] zones, Rectangle rectangle)
        {
            List<NavZone> zonesInRectangle = new List<NavZone>();
            int count = zones.Length;
            for (int i = 0; i < count; i++)
            {
                NavZone zone = zones[i];
                if (zone.GetRectangle().Intersects(rectangle))
                {
                    zonesInRectangle.Add(zone);
                }
            }
            return zonesInRectangle.ToArray();
        }

        private NavZone[] GetZonesStarting(NavZone[] zones, Rectangle rectangle)
        {
            List<NavZone> zonesInRectangle = new List<NavZone>();
            int count = zones.Length;
            for (int i = 0; i < count; i++)
            {
                NavZone zone = zones[i];
                if (rectangle.Contains(new Point(zone.Left, zone.Top)))
                {
                    zonesInRectangle.Add(zone);
                }
            }
            return zonesInRectangle.ToArray();
        }

    }
}
